// --------------------------------------------------------------------
//   name 	: ReportCache
//   desc 	: Adds a report cache and report summary option
//   version 	: 0.2 Beta 01
//   dev 	: Timas
// --------------------------------------------------------------------
// DEPENDENCIES
// 
// --------------------------------------------------------------------
// CHANGE HISTORY
// 0.1 	Initial Release
// 0.2	Beta 01 Updated Layout and added more features
// 0.2  Beta 02 Added Brief Report (Single line per report)
// 0.2  Beta 03 Added Attacker to distinguish attacks per village
// 0.3  Beta Added sorting function to table.
// --------------------------------------------------------------------
// Report Array Format
//	id 			: report id
//	timestamp 		: time
//	timefull 		: time in full format
//	attacker 		: Attacker HTML player name
//	attackvillageid 	: Attacker Village ID
//	attackvillagefull 	: Attacker Village HTML Link
//	attackvillagename 	: Attacker Village Name
//	attackcoords 		: Co-ords of attacker
//	defender 		: Defender HTML Name (i.e. who we are attacking)
//	defendvillageid 	: Defender Village ID
//	defendvillagefull 	: Defender Village HTML link
//	defendvillagename 	: Defender Village Name
//	defendcoords 		: Co-ords of Defender (i.e. who we are attacking)
//	resources 		: resource array
//	buildings 		: building arrary
// --------------------------------------------------------------------
	plugins.reportcache = {

//	production at normal speed
//	_production : [
//	30, 35, 41, 47,  55,  64,  74,  86, 100, 117, // level 1-10
//	136,158,184,214, 249, 289, 337, 391, 455, 530, // level 11-20
// 	616,717,833,969,1127,1311,1525,1744,2063,2400, // level 21-30
// ],
//	warehouse storage
		_warehouse_storage : [
	0,1000,1229,1512,1859,2285,2810,3454,4247,5222,6420, // level 0,1-10
	7893,9705,11932,14670,18037,22177,27266,33523,41217,50675, // level 11-20
	62305,76604,94184,115798,142373,175047,215219,264611,325337,400000 // level 21-30
 ],
//	production at 0.75 Speed
		_production : [
	23, 26, 30, 35,  41,  48,  56,  65, 75, 88, // level 1-10
	102,119,138,160, 187, 217, 252, 294, 342, 397, // level 11-20
	462,537,625,727,846,984,1144,1331,1548,1800, // level 21-30
 ],
//	hideout storage
		_hideout_storage : [
	0,150,200,267,356,474,632,843,1125,1500,2000, // level 1-10
 ],


// --------------------------------------------------------------------
// Function : getReportsArray
// Returns latest report for all villages
// --------------------------------------------------------------------
getReportsArray : function() {
	 var reports = getValue("reports");
	 var reportsArr = [];
	 for(var k in reports) {
		 reportsArr.push(reports[k]);
	 }
	 return reportsArr;
 },

// --------------------------------------------------------------------
// Function : getReportsbyVillage
// Returns latest report for specific village
// --------------------------------------------------------------------
 getReportsByVillage : function() {
	 var reports = getValue("reports");
	 var ret = {};
	 for(var v in reports) {
		 var report = reports[v];
		 var coords = report.defendcoords.join('|');
			// only put in object if it's not already in there or if it's fresher
		 if(!ret[coords] || ret[coords].timestamp < report.timestamp) {
			 ret[coords] = report;
		 }
	 }
	 return ret;
 },

// --------------------------------------------------------------------
// Function : getReportForCoord
// --------------------------------------------------------------------
 getReportForCoord : function(coord) {
	 return plugins.reportcache.getReportsByVillage()[coord];
 },

// --------------------------------------------------------------------
// Function : enhance_game_map
// Add "Last Report" Timefull on map popup when browse towns.
// --------------------------------------------------------------------
 enhance_game_map : function() {
	 var old_map_popup = unsafeWindow.map_popup;
	 $("#info_content #info_extra_info").after("<tr><td>Last report</td><td id=\"info_reportcache\"></td></tr>");
	 setFunc("map_popup", function map_popup(title, bonus_image, bonus_text, points, owner, ally, village_groups, moral, village_id, source_id) {
		 old_map_popup(title, bonus_image, bonus_text, points, owner, ally, village_groups, moral, village_id, source_id);
		 window.setTimeout(function() {
			 var coord=title.match(/\((-?\d+\|-?\d+)\)/)[1];
			 var report = plugins.reportcache.getReportForCoord(coord);
			 $("#info_reportcache").html(report?report.timefull:"");
		 }, 0);
	 });
 },

// --------------------------------------------------------------------
// Function : get_report_html
// Returns HTML Code for Report Summary (long Version)
// --------------------------------------------------------------------
 _get_report_html : function() {
	 var html="";
	 var report;
	 var reports = plugins.reportcache.getReportsByVillage();
	 var villages = twe.myVillages();
	 var v = villages[personals.getCurrentVillage()];
	 var vcoords = [v.x,v.y];
	 var i=0;
	 html += "<table width=90%><tr><td align=right><small><i>"+servertime.toString().replace(/GMT\+1000 \(AUS Eastern Standard Time\)/g,"")+"</i></small></td></tr><table>"
	 for(var report_id in reports) {
		 report = reports[report_id];
			//log(3, "reportcache report="+uneval(report));
			// age in seconds
			// TODO: remove me - fix for incorrect reports
		 if(report.timestamp.getTime) { report.timestamp = report.timestamp.getTime(); }
		 var age = (servertime.getTime()-report.timestamp)/1000;
		 html += "<table border=0 width=90% class=\"report\"><tr><th>Target</th><td>"+report.defender+"</td>";
		 html += "<th>Village</th><td colspan=3><a href=\"game.php?village="+personals.getCurrentVillage()+"&amp;screen=info_village&amp;id="+report.defendvillageid+"\">"+report.defendvillagefull+"</a></td><td align=right><a href=\"game.php?village="+personals.getCurrentVillage()+"&amp;screen=report&amp;mode=attack&amp;view="+report.id+"\">Open report</a></td></tr>";
		 html += "<tr><th>Date</th><td>"+report.timefull+"</td>";
		 html += "<th>Distance</th><td>"+plugins.distancecalc.get_distance(vcoords,report.defendcoords)+"</td>";
		 		 
//		 html += "<th>Age</th><td>"+servertime+"-"+servertime.getTime()+"*"+report.timestamp+"*"+age+"</td>";
		 html += "<th>Age</th><td>"+Math.round(age/3600*100)/100+"hrs</td>";
		 html += "<td width=15% align=right><a href=\"javascript:deletereport('"+report.id+"')\">Delete Report</a></tr>";

		 html += "<tr><td colspan=\"0\">";
/*
		 html += "<table><tr><th>Buildings</th><td>\n";
		 for(var bname in report.buildings) {
				//html += "<tr>\n";
				//html += "<td>"+plugins.reportcache._buildings[bname]+"</td>\n";
				//html += "<td>"+report.buildings[bname]+"</td>\n";
				//html += "</tr>\n";
		 html += plugins.reportcache._buildings[bname]+" <b>(Level "+report.buildings[bname]+")</b><br/>";
	 }
		 html += "</td></tr></table>";
*/
		 html += "<table border=0 width=100%>";
		 html += "<tr><th>Resources</th><th><img src=\"/graphic/holz.png\"></th><th><img src=\"/graphic/lehm.png\"></th><th><img src=\"/graphic/eisen.png\"</th><th><img src=\"/graphic/res.png\"></th><th>&nbsp;&nbsp;&nbsp;&nbsp;</th><th><img src=\"/graphic/holz.png\"></th><th><img src=\"/graphic/lehm.png\"></th><th><img src=\"/graphic/eisen.png\"</th><th><img src=\"/graphic/res.png\"></th><th>&nbsp;&nbsp;&nbsp;&nbsp;</th><th><img src=\"/graphic/holz.png\"></th><th><img src=\"/graphic/lehm.png\"></th><th><img src=\"/graphic/eisen.png\"</th><th><img src=\"/graphic/res.png\"></th><th><img src=\"graphic/unit/unit_light.png\"></th><th>Time</th></tr>";
		 var sum = 0;
		 for(var i in report.resources) { sum += report.resources[i]; }
		 html += "<tr><th>Last</th><td>"+report.resources.join("</td><td>")+"</td><td>"+sum+"</td><th>Build</th>";
		 if(report.buildings.wood||report.buildings.stone||report.buildings.iron) {
			 html += "<td>"+report.buildings.wood+"</td><td>"+report.buildings.stone+"</td><td>"+report.buildings.iron+"</td><td>"+report.buildings.storage+"</td><th>Est</th>";
			 var resources = report.resources.slice(); // slice = clone array
			 resources[0] += Math.round(plugins.reportcache._production[report.buildings.wood-1]*(age/3600));
			 resources[1] += Math.round(plugins.reportcache._production[report.buildings.stone-1]*(age/3600));
			 resources[2] += Math.round(plugins.reportcache._production[report.buildings.iron-1]*(age/3600));
			 var maxstorage = plugins.reportcache._warehouse_storage[report.buildings.storage]-plugins.reportcache._hideout_storage[report.buildings.hide];
 			 for(var i in resources) { if (resources[i] > maxstorage) resources[i] = maxstorage; }
			 sum = 0;
			 for(var i in resources) { sum += resources[i]; }
			 if (sum != 0){
				  var cavneed = sum / 80;
				  cavneed = Math.ceil(cavneed);
			  }
			 for(var i in resources) { 
				if (resources[i] == maxstorage ) { 
					html += "<td style='color:red; font-weight: bold'>"+resources[i]+"</td>"; 
			 	} else { 
					html += "<td>"+resources[i]+"</td>"; 
				}	
			 }
			 var fulltime = Math.round((maxstorage - resources[0])/plugins.reportcache._production[report.buildings.wood-1]*100)/100;
			 if (Math.round((maxstorage - resources[1])/plugins.reportcache._production[report.buildings.stone-1]*100)/100 > fulltime) { 						fulltime = Math.round((maxstorage - resources[1])/plugins.reportcache._production[report.buildings.stone-1]*100)/100; }
			 if (Math.round((maxstorage - resources[2])/plugins.reportcache._production[report.buildings.iron-1]*100)/100 > fulltime) {
				fulltime = Math.round((maxstorage - resources[2])/plugins.reportcache._production[report.buildings.iron-1]*100)/100;}
 			 html += "<td>"+sum+"</td><td>"+cavneed+"</td><td width=8%> "+fulltime+" hrs</td></tr>";
		 }
		 html += "</td></tr></table>";
		 html += "</td></tr></table>";
		 html += "<hr>";
		 i++;
	 }

	 if(i==0) html += "No reports found - look at some reports first";
	 return html;
 },

// --------------------------------------------------------------------
// Function : _get_report_html_brief
// Return a brief single line version of the reportcache
// --------------------------------------------------------------------
 _get_report_html_brief : function() {
	 var html="";
	 var report;
	 var reports = plugins.reportcache.getReportsByVillage();
	 var villages = twe.myVillages();
	 var v = villages[personals.getCurrentVillage()];
	 var vcoords = [v.x,v.y];
	 var i=0;
	 html += "<hr><h3>Report Cache Summary</h3>";
	 html += "<table><tr><td align=right><small><i>Server Time : "+servertime.toString()+"</i></small></td></tr><table>"
	 html += "<table id='mytable' border=1 width=800 class=\"vis\"><thead><tr><th width=50%>Village</th><th><img src=\"/graphic/command/return.png\"></th><th width=10%>Distance</th><th width=10%>Total:</th><th width=10%>Cav</th><th width=10%>Full In</th><th>QuickFill</th></tr></thead><tbody>";
	 for(var report_id in reports) {
		 report = reports[report_id];
			//log(3, "reportcache report="+uneval(report));
			// age in seconds
			// TODO: remove me - fix for incorrect reports
		if (report.attackvillagename==v.name) {
		 if(report.timestamp.getTime) { report.timestamp = report.timestamp.getTime(); }
		 var age = (servertime.getTime()-report.timestamp)/1000;
		 html += "<tr><td><a href=\"game.php?village="+personals.getCurrentVillage()+"&amp;screen=info_village&amp;id="+report.defendvillageid+"\">"+report.defendvillagefull;
		 if (plugins.attackcache.getAttacksByCoords(report.defendcoords.join('|')))
		 { html +="</a></td><td><img src=\"/graphic/command/return.png\"></td>"; }
		 else
		 { html +="</a></td><td>X</td>"; }
		 // took out <td>"+report.attackvillagename+"</td>
		 html += "<td align=center>"+plugins.distancecalc.get_distance(vcoords,report.defendcoords)+"</td>";
		 var sum = 0;
		 for(var i in report.resources) { sum += report.resources[i]; }
		 if(report.buildings.wood||report.buildings.stone||report.buildings.iron) {
			 var resources = report.resources.slice(); // slice = clone array
			 resources[0] += Math.round(plugins.reportcache._production[report.buildings.wood-1]*(age/3600));
			 resources[1] += Math.round(plugins.reportcache._production[report.buildings.stone-1]*(age/3600));
			 resources[2] += Math.round(plugins.reportcache._production[report.buildings.iron-1]*(age/3600));
			 var maxstorage = plugins.reportcache._warehouse_storage[report.buildings.storage]-plugins.reportcache._hideout_storage[report.buildings.hide];
 			 for(var i in resources) { if (resources[i] > maxstorage) resources[i] = maxstorage; }
			 sum = 0;
			 for(var i in resources) { sum += resources[i]; }
			 if (sum != 0){
				  var cavneed = sum / 80;
				  cavneed = Math.ceil(cavneed);
			  }
			 var fulltime = Math.round((maxstorage - resources[0])/plugins.reportcache._production[report.buildings.wood-1]*100)/100;
			 if (Math.round((maxstorage - resources[1])/plugins.reportcache._production[report.buildings.stone-1]*100)/100 > fulltime) { 						fulltime = Math.round((maxstorage - resources[1])/plugins.reportcache._production[report.buildings.stone-1]*100)/100; }
			 if (Math.round((maxstorage - resources[2])/plugins.reportcache._production[report.buildings.iron-1]*100)/100 > fulltime) {
				fulltime = Math.round((maxstorage - resources[2])/plugins.reportcache._production[report.buildings.iron-1]*100)/100;}
 			 html += "<td align=center>"+sum+"</td><td align=center>"+cavneed+"</td><td align=center> "+fulltime+" hrs</td>";
 			 html += "<td align=center><a href=\"javascript:insertUnit(document.forms[0].light,"+cavneed+");insertUnit(document.forms[0].spy,1);insertUnit(document.forms[0].x,"+report.defendcoords[0]+");insertUnit(document.forms[0].y,"+report.defendcoords[1]+")\">Fill</a>";
 			 html += "</td></tr>";
		 }
		i++;
		}
	 }
	 html += "</tbody></table>";
	 html +="<script type=\"text/javascript\">var t = new SortableTable(document.getElementById('mytable'), 100);</script>"
	 if(i==0) html = "No reports found - look at some reports first";
	 return html;
 },

// --------------------------------------------------------------------
// Function : _generate_report
// Collects the information from the attack report
// --------------------------------------------------------------------
 _generate_report : function() {
		// find report id
	 var tmp=location.href.match(/view=(\d+)/);
	 if(!tmp) return false;
	 var report_id = tmp[1];

		// find time report was sent
	 var timeTD = $("table.vis:eq(1) tr:eq(1) td:last")[0];
	 log(1,"Report Time: "+timeTD.innerHTML);
	 var time;
	 if(/tribalwars.se/.test(location.host)) {
			//example: 19 04 08 21:50
		 var tmp = timeTD.innerHTML.match(/(\d+) (\d+) (\d+) (\d+):(\d+)/);
			// this is a Y3K bug waiting to happen!
		 time = new Date("20"+tmp[3], parseInt(tmp[2])-1, tmp[1], tmp[4], tmp[5]).getTime();
	 } else if(/tribalwars.fr/.test(location.host)) {
			//example: 19.04.08 Ã  17:55
		 var tmp = timeTD.innerHTML.match(/(\d+)\.(\d+)\.(\d+) Ã  (\d+):(\d+)/);
		 time = new Date("20"+tmp[3], parseInt(tmp[2])-1, tmp[1], tmp[4], tmp[5]).getTime();
	 } else if(/gr/.test(location.host)) {
			//example: 19-04-08 17:55
		 var tmp = timeTD.innerHTML.match(/(\d+)\-(\d+)\-(\d+) (\d+):(\d+)/);
		 time = new Date("20"+tmp[3], parseInt(tmp[2])-1, tmp[1], tmp[4], tmp[5]).getTime();
		 log(1,"Greek Time: "+time);	
	 } else {
		 time = Date.parse(timeTD.innerHTML);
	 }
	 var report = {
		id : report_id,
	   	timestamp : time,
		timefull : timeTD.innerHTML,
	 };

	 // table:eq(2) is Luck table
  	 // Find which village attacked
	 var attacker = $("table[width='100%']:has(table.vis img[src*='graphic/unit/unit_spear.png']):eq(0)")[0];
	 var AttackPlayerA = $('tr:first > th:eq(1)', attacker)[0];
	 if(!AttackPlayerA) {
		 log(1, "Couldn't find attack player");
		 return;
	 }
	 report.attacker = AttackPlayerA.innerHTML; // TODO: strip HTML
	 var AttackVillageA = $('tr:eq(1) > td:eq(1) a', attacker)[0];
	 tmp = AttackVillageA.href.match(/&id=(\d+)/);
	 report.attackvillageid = tmp[1];
	 tmp = AttackVillageA.innerHTML.match(/(.+) \((-?\d+\|-?\d+)\)(?: (K\d+))?/);
	 report.attackvillagefull = AttackVillageA.innerHTML;
	 report.attackvillagename = tmp[1];
	 report.attackcoords = tmp[2].split("|");
	 
	 // find target-Defender table
	 var target = $("table[width='100%']:has(table.vis img[src*='graphic/unit/unit_spear.png']):eq(1)")[0];
		//alert(target.innerHTML);
		//var target = $('table.main table.vis td[colspan=2] > table:eq(3)')[0];
		// this is incorrect for market
	 var targetPlayerA = $('tr:first > th:eq(1)', target)[0];
	 if(!targetPlayerA) {
		 log(1, "Couldn't find target player");
		 return;
	 }
	 report.defender = targetPlayerA.innerHTML; // TODO: strip HTML
	 var targetVillageA = $('tr:eq(1) > td:eq(1) a', target)[0];
	 tmp = targetVillageA.href.match(/&id=(\d+)/);
	 report.defendvillageid = tmp[1];
	 tmp = targetVillageA.innerHTML.match(/(.+) \((-?\d+\|-?\d+)\)(?: (K\d+))?/);
	 report.defendvillagefull = targetVillageA.innerHTML;
	 report.defendvillagename = tmp[1];
	 report.defendcoords = tmp[2].split("|");
		
		//var targetUnits = $('tr:eq(2)', target)[0].innerHTML;

		// find resource levels
	 var resourceTD = $('td:has(> img[src$="graphic/holz.png"])')[0];
	 newHtml = resourceTD.innerHTML.replace(/<span.*?<\/span>/g,""); // remove spans
	 newHtml = newHtml.replace(/<img.*?>/g,""); // remove images
	 var resources = newHtml.split(" ");
	 resources.length=3;
	 resources = resources.map(function(element) {return parseInt(element);});
	 report.resources = resources;

		// find building levels
	 var buildingsTD = $('tr:has(> td > img[src$="graphic/holz.png"]) + tr:first > td')[0];
	 report.buildings = !buildingsTD ? {} : plugins.reportcache._get_buildings(buildingsTD);
	 return report;
 },
 _buildings : null,

// --------------------------------------------------------------------
// Function : getBuildings
// --------------------------------------------------------------------
 getBuildings : function() {
	 if(!plugins.reportcache._buildings)
	 plugins.reportcache._buildings = getValue("buildings");
	 return plugins.reportcache._buildings;
 },

// --------------------------------------------------------------------
// Function : enhance_game_main
// --------------------------------------------------------------------
 'enhance_game_main' : function() {
	 var buildings = {};
	 $('table[class=vis]:has(tr:eq(1) td:eq(6)) tr td:first-child').each(function() {
		 var tmp = this.innerHTML.match(/screen=(.*?)"><img.*> (.*)</);
		 buildings[tmp[1]] = tmp[2];
	 });
	 setValue("buildings", buildings);

 },
 
 'enhance_game_place' : function() {
	 setFunc("SortableTable", function(TableID) { window.setTimeout(function() {
		 plugins.reportcache._sorttable(TableID);
	 }, 0)});
//	 $("table.main p").after("<table><tr><td width=100></td><td>"+plugins.reportcache._get_report_html_brief()+"</td></tr</table>");
 	 $("table.main hr:first").before("<table><tr><td>"+plugins.reportcache._get_report_html_brief()+"</td></tr></table>");

	 
 },

// --------------------------------------------------------------------
// Function : enhance_game_report
// Adds additional items on the menu column (Report Brief and Report Summary)
// Adds global functions for reportcache, reportcache_brief and deletereport
// --------------------------------------------------------------------
 enhance_game_report : function() {
	 var report = plugins.reportcache._generate_report();
	 if(report) plugins.reportcache._update_report(report);

	 $('table.vis:first').append('<tr><td><a href="javascript:reportcache_brief()">Report Brief</a></td></tr>');
	 $('table.vis:first').append('<tr><td><a href="javascript:reportcache()">Report Summary</a></td></tr>');
	 setFunc("reportcache", function() { window.setTimeout(function() {
		$("table.main table:first tr:first > td:eq(1)").html(plugins.reportcache._get_report_html());
	 }, 0)});
	 setFunc("reportcache_brief", function() { window.setTimeout(function() {
		$("table.main table:first tr:first > td:eq(1)").html(plugins.reportcache._get_report_html_brief());
	 }, 0)});
	 setFunc("deletereport", function(reportid) { window.setTimeout(function() {
		 plugins.reportcache._delete_report(reportid);
		 $("table.main table:first tr:first > td:eq(1)").html(plugins.reportcache._get_report_html())
	 }, 0)});

 },

// --------------------------------------------------------------------
// Function : 
// --------------------------------------------------------------------
 _delete_report : function(reportid) {
	 var reports = getValue("reports");
	 delete reports[reportid];
	 setValue("reports", reports);
	 log(3, "reportcache delete report="+reportid);
 },

// --------------------------------------------------------------------
// Function : 
// --------------------------------------------------------------------
 _update_report : function(report) {
	 var reports = getValue("reports");
	 if(!reports) reports = {};
	 // remove older reports from the cache
	 for(var v in reports) {
	 	if ((report.defendcoords.join('|') == reports[v].defendcoords.join('|'))&&(report.timestamp > reports[v].timestamp)) {
	 	delete reports[v];}
	 }
	 reports[report.id] = report;
	 setValue("reports", reports);
	 log(3, "reportcache updated report="+uneval(report));
 },

// --------------------------------------------------------------------
// Function : _get_buildings
// --------------------------------------------------------------------
 _get_buildings : function(buildingsTD) {
// --------------------------------------------------------------------
// Format of building report
//	 Village Headquarters <b>(Level 29)</b><br>
//	 Barracks <b>(Level 21)</b><br>
//	 Stable <b>(Level 4)</b><br>
//	 Smithy <b>(Level 8)</b><br>
//	 Rally point <b>(Level 1)</b><br>
//	 Statue <b>(Level 1)</b><br>
//	 Market <b>(Level 19)</b><br>
//	 Timber camp <b>(Level 24)</b><br>
//	 Clay pit <b>(Level 19)</b><br>
//	 Iron mine <b>(Level 16)</b><br>
//	 Farm <b>(Level 16)</b><br>
//	 Warehouse <b>(Level 24)</b><br>
//	 Hiding place <b>(Level 3)</b><br>
//	 Wall <b>(Level 2)</b><br>		
// --------------------------------------------------------------------
	 var reverse = array_flip(plugins.reportcache.getBuildings());
	 var buildingsText = buildingsTD.innerHTML.replace(/<.+?>/g,""); //this can also contain the loyalty loss.
	 var buildings = {};
	 $.each(buildingsText.split('\n'), function(i, buildingText) {
		 var tmp = buildingText.match(/\s*(.*) \(.*?(\d+)\)/);
		 if(!tmp) return; // don't know what this is -- return silently
		 building = tmp[1];
		 var level = tmp[2];
		 if(!reverse[building]) {
			 log(2, "reportcache: Unknown building: "+building);
			 return;
		 }
		 buildings[reverse[building]] = level;
			//if we want to display the full building name i suggest we grab the raw HTML. Use this code instead:
			//buildings[reverse[building]] = {level:level, text:buildingText};
	 });
	 return buildings;
	 },

// --------------------------------------------------------------------
// Function : sorttable
// --------------------------------------------------------------------
_sorttable : function(tableEl) {

    this.tbody = tableEl.getElementsByTagName('tbody');
    this.thead = tableEl.getElementsByTagName('thead');
    this.tfoot = tableEl.getElementsByTagName('tfoot');

    this.getInnerText = function (el) {
        if (typeof(el.textContent) != 'undefined') return el.textContent;
        if (typeof(el.innerText) != 'undefined') return el.innerText;
        if (typeof(el.innerHTML) == 'string') return el.innerHTML.replace(/<[^<>]+>/g,'');
    }

    this.getParent = function (el, pTagName) {
        if (el == null) return null;
        else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
            return el;
        else
            return this.getParent(el.parentNode, pTagName);
    }

    this.sort = function (cell) {

        var column = cell.cellIndex;
        var itm = this.getInnerText(this.tbody[0].rows[1].cells[column]);
        var sortfn = this.sortCaseInsensitive;

        if (itm.match(/\d\d[-]+\d\d[-]+\d\d\d\d/)) sortfn = this.sortDate; // Date format mm-dd-yyyy
        if (itm.replace(/^\s+|\s+$/g,"").match(/^[\d\.]+$/)) sortfn = this.sortNumeric;

        this.sortColumnIndex = column;

        var newRows = new Array();
        for (j = 0; j < this.tbody[0].rows.length; j++) {
            newRows[j] = this.tbody[0].rows[j];
        }

        newRows.sort(sortfn);

        if (cell.getAttribute("sortdir") == 'down') {
            newRows.reverse();
            cell.setAttribute('sortdir','up');
        } else {
            cell.setAttribute('sortdir','down');
        }

        for (i=0;i<newRows.length;i++) {
            this.tbody[0].appendChild(newRows[i]);
        }

    }

    this.sortCaseInsensitive = function(a,b) {
        aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]).toLowerCase();
        bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]).toLowerCase();
        if (aa==bb) return 0;
        if (aa<bb) return -1;
        return 1;
    }

    this.sortDate = function(a,b) {
        aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]);
        bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]);
        date1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
        date2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
        if (date1==date2) return 0;
        if (date1<date2) return -1;
        return 1;
    }

    this.sortNumeric = function(a,b) {
        aa = parseFloat(thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]));
        if (isNaN(aa)) aa = 0;
        bb = parseFloat(thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]));
        if (isNaN(bb)) bb = 0;
        return aa-bb;
    }

    // define variables
    var thisObject = this;
    var sortSection = this.thead;

    // constructor actions
    if (!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length > 0)) return;

    if (sortSection && sortSection[0].rows && sortSection[0].rows.length > 0) {
        var sortRow = sortSection[0].rows[0];
    } else {
        return;
    }

    for (var i=0; i<sortRow.cells.length; i++) {
        sortRow.cells[i].sTable = this;
        sortRow.cells[i].onclick = function () {
            this.sTable.sort(this);
            return false;
        }
    }
   },
    
// --------------------------------------------------------------------
// Information array 
// --------------------------------------------------------------------
   'info' : {
   'mandatory' : false,
   'name' : "ReportCache",
   'desc' : "Adds a report cache and report summary option",
   'version' : "0.1",
   'dev' : "Timas"
  }
	};